/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pb138.XmlWebServlets;

import cz.muni.fi.pb138.XmlDataBase.DatabaseException;
import cz.muni.fi.pb138.XmlDataBase.Medium;
import cz.muni.fi.pb138.XmlDataBase.MediumManagerImpl;
import cz.muni.fi.pb138.XmlDataBase.ODFTransformation;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;

/**
 *
 * @author Tomas
 */
@WebServlet(name = "VideoWebServlet",
urlPatterns = {VideoWebServlet.ACTION_LIB, VideoWebServlet.ACTION_ADD_MEDIUM,
    VideoWebServlet.ACTION_ALL_MOVIES,VideoWebServlet.ACTION_EXPORT_ODF,
    VideoWebServlet.ACTION_IMPORT_ODF,VideoWebServlet.ACTION_FIND})
public class VideoWebServlet extends HttpServlet {

    static final String ACTION_FIND = "/Find";
    static final String ACTION_LIB = "/Lib";
    static final String ACTION_IMPORT_ODF = "/ImportODF";
    static final String ACTION_EXPORT_ODF = "/ExportODF";
    static final String ACTION_ADD_MEDIUM = "/Add";    
    static final String ACTION_ALL_MOVIES = "/Movies";
    static final String ACTION_DELETE_MEDIUM = "/Delete";
    static final String ATTRIBUTE_MEDIUMS = "mediums";
    static final String ATTRIBUTE_MEDIUM_FORM = "mediumForm";
    static final String ATTRIBUTE_ERROR = "error";
    static final String JSP_LIB = "/WEB-INF/jsp/lib.jsp";
    static final String JSP_ADD_MEDIUM = "/WEB-INF/jsp/add.jsp";
    static final String JSP_ADD_MOVIE = "/WEB-INF/jsp/addMovie.jsp";
    static final String JSP_MOVIES = "WEB-INF/jsp/movies.jsp";    
    private MediumManagerImpl mediumManager = prepareSource();

    /**
     * prepare connection to database
     * 
     * @return MediumManagerImpl with database connection  
     */
    private MediumManagerImpl prepareSource() {
        InputStream in = null;
        try {
            Properties prop = new Properties();
            in = getClass().getResourceAsStream("user.properties");
            prop.load(in);
            
            return new MediumManagerImpl(prop.getProperty("collection"),prop.getProperty("user"),
                    prop.getProperty("password"));
        } catch (Exception ex) {
            System.err.println("Cannot load db");
            return null;
        } finally{
            if(in != null) try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Display home page lib.jsp
     * Provides the main functionality.
     * Contain buttons to add and remove medium, import/export xml to ODF
     * and find medium with movie
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void videoLib(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        if (request.getParameter("action") != null) {
            if (request.getParameter("action").equals(ACTION_DELETE_MEDIUM)) {
                deleteMedium(request, response);
            }
        }
        try {
            List<String> mediums = mediumManager.getAllMediumsIds();
            String mediumsXml = transform(mediums);
            request.setAttribute("mediumXml", mediumsXml);
            request.getRequestDispatcher(JSP_LIB).forward(request, response);
        } catch (DatabaseException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NullPointerException ex) {
            request.getRequestDispatcher(JSP_LIB).forward(request, response);
        }
    }

    
    /**
     * Function works with page add.jsp which contains dynamically form to add new medium
     * with movies into database.
     * Medium name is required. 
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void addMediumToLib(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        if (request.getMethod().equals("POST")) {
            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
            } else {
                MediumForm mediumForm = MediumForm.extractFromRequest(request);
                StringBuilder errors = new StringBuilder();
                Medium medium = mediumForm.validateAndToMedium(errors);
                if (medium == null) {
                    request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
                    request.setAttribute(ATTRIBUTE_MEDIUM_FORM, mediumForm);
                    request.getRequestDispatcher(JSP_ADD_MEDIUM).forward(request, response);
                } else {
                    try {
                        mediumManager.createMedium(medium);
                        response.sendRedirect(request.getContextPath());
                    } catch (DatabaseException ex) {
                        System.err.println("Cannot store medium: " + medium + "into db ");
                    }
                }
            }
        } else {
            request.setAttribute(ATTRIBUTE_MEDIUM_FORM, new MediumForm());
            request.getRequestDispatcher(JSP_ADD_MEDIUM).forward(request, response);
        }
    }

    /**
     * Page with all movies in database. Provides button to home page.
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void getAllMovies(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            List<String> mediums = mediumManager.getAllMediumsIds();

            String mediumsXml = "";
            for (String medium : mediums) {

                Document doc = mediumManager.getMediumAsDom(medium);
                DOMSource dom = new DOMSource(doc);

                String mediumXml = mediumManager.transformToString(dom, true);
                if (mediumXml != null) {
                    mediumsXml += mediumXml;
                }
            }
            
            request.setAttribute("mediumXml", mediumsXml);
            request.getRequestDispatcher(JSP_MOVIES).forward(request, response);


        } catch (DatabaseException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NullPointerException ex) {
            request.getRequestDispatcher(JSP_MOVIES).forward(request, response);
        }        
    }   

    /**
     * Delete selected medium from database.
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void deleteMedium(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            String id = request.getParameter("id");
            mediumManager.deleteMedium(id);
            
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NullPointerException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DatabaseException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Export database into .odf file. User set name of file, which is save
     * into netbeans default.
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void exportToODF(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        if (request.getMethod().equals("POST")) {
            try {
                String filename = request.getParameter("fname") + ".ods";

                List<String> mediumsId = mediumManager.getAllMediumsIds();
                ODFTransformation odf = new ODFTransformation();
                odf.exportODF(mediumsId, mediumManager, filename);
                response.sendRedirect(request.getContextPath());
            } catch (DatabaseException ex) {
                Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Show page with mediums, that have given movie.
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void findMovies(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            String movie = request.getParameter("movieName");
            Collection<String> mediums = mediumManager.getMediumsWithMovie(movie);
            String mediumsXml = "";            
            for (String medium : mediums) {

                Document doc = mediumManager.getMediumAsDom(medium);
                DOMSource dom = new DOMSource(doc);

                String mediumXml = mediumManager.transformToString(dom, true);
                if (mediumXml != null) {
                    mediumsXml += mediumXml;
                }
            }
            
            request.setAttribute("mediumXml", mediumsXml);
            request.getRequestDispatcher(JSP_MOVIES).forward(request, response);            

        } catch (DatabaseException ex) {
            Logger.getLogger(VideoWebServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NullPointerException ex) {
            request.getRequestDispatcher(JSP_MOVIES).forward(request, response);
        }        
    }
    
    /**
     * Import database from .ods file into database. 
     * Choosen file must be with .ods format.
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    public void importFromODF(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        if (request.getMethod().equals("POST")) {

            String path = request.getParameter("ipath");
            ODFTransformation odf = new ODFTransformation();
            File file = new File(path);
            System.err.println(path + " vitaj");
            odf.importODF(file, mediumManager);
            response.sendRedirect(request.getContextPath());

        }
    }

    /** Transform List of medium ids(String) into HTML code
     * @param mediums all medium in database
     * @return
     * @throws DatabaseException 
     */
    private String transform(List<String> mediums) throws DatabaseException {
        String transformedOutput = "";
        for (String medium : mediums) {
            Document doc = mediumManager.getMediumAsDom(medium);
            DOMSource dom = new DOMSource(doc);
            String mediumXml = mediumManager.transformToString(dom, false);
            if (mediumXml != null) {
                transformedOutput += mediumXml;
            }
        }
        return transformedOutput;
    }

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        if (request.getServletPath().equals(ACTION_LIB)) {
                        
            videoLib(request, response);
        } else if (request.getServletPath().equals(ACTION_ADD_MEDIUM)) {
            
            addMediumToLib(request, response);
        } else if (request.getServletPath().equals(ACTION_ALL_MOVIES)) {
            
            getAllMovies(request, response);
        } else if (request.getServletPath().equals(ACTION_DELETE_MEDIUM)) {
            
            deleteMedium(request, response);
        } else if (request.getServletPath().equals(ACTION_EXPORT_ODF)) {
            
            exportToODF(request, response);
        } else if (request.getServletPath().equals(ACTION_IMPORT_ODF)) {
            
            importFromODF(request, response);
        } else if (request.getServletPath().equals(ACTION_FIND)) {
            
            findMovies(request, response);
            importFromODF(request, response);
        } else {
            throw new RuntimeException("Unknow operation " + request.getServletPath());
        }

    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
